﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
//using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System.Windows.Media.Imaging;
using Microsoft.Phone.Applications.Common;
using FarseerPhysics;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Factories;
using FarseerPhysics.SamplesFramework;
using FarseerPhysics.Dynamics.Joints;
using LineBatchTester;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;

namespace BootyShaker
{
    public partial class GamePage : PhoneApplicationPage
    {
        ContentManager contentManager;
        GameTimer timer;
        SpriteBatch spriteBatch;
        Texture2D backgroundTexture;
        World World;
        //Body _rectangle;
        public GamePage()
        {
            InitializeComponent();

            // Get the content manager from the application
            contentManager = (Application.Current as App).Content;
            if (World == null)
            {
                World = new World(Vector2.Zero);
            }
            else
            {
                World.Clear();
            }
            World.Gravity = new Vector2(0f, 10f);

            //_border = new Border(World, this, SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport);



            //joint = new FarseerPhysics.Dynamics.Joints.FixedLineJoint(_rectangle, _rectangle.Position, Vector2.Zero);
            //joint.MaxForce = 1000.0f * _rectangle.Mass;
            //joint.Enabled = true;
            // World.AddJoint(joint);
            //SetUserAgent(_rectanglejoint 100f, 100f);

            // Create a timer for this page
            timer = new GameTimer();
            timer.UpdateInterval = TimeSpan.FromTicks(333333);
            timer.Update += OnUpdate;
            timer.Draw += OnDraw;
            AccelerometerHelper.Instance.ReadingChanged += new EventHandler<AccelerometerHelperReadingEventArgs>(OnAccelerometerHelperReadingChanged);
            startstop(true);


        }

      

        //Matrix _projection;
        //FixedDistanceJoint joint;
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            // Set the sharing mode of the graphics device to turn on XNA rendering
            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);

            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice);

            LineBatch.Init(SharedGraphicsDeviceManager.Current.GraphicsDevice);
           
            backgroundTexture = new Texture2D(SharedGraphicsDeviceManager.Current.GraphicsDevice, App.ShakeImageTransformed.PixelWidth, App.ShakeImageTransformed.PixelHeight, false, SurfaceFormat.Color);

            backgroundTexture.SetData(App.BGRAToRGBA(App.ShakeImageTransformed));

            // TODO: use this.content to load your game content here
            foreach (ShakeObject so in App.shakeObjects)
            {
                so.LoadImage(SharedGraphicsDeviceManager.Current.GraphicsDevice, World);

                //joint.DampingRatio= 2f;
            }

           

            // Start the timer
            timer.Start();
            startstop(true);
            base.OnNavigatedTo(e);
        }

        //Texture2D testTxt;

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // Stop the timer
            timer.Stop();


            // Set the sharing mode of the graphics device to turn off XNA rendering
            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false);
            startstop(false);
            base.OnNavigatedFrom(e);
        }




        private double GetDelta()
        {
            long tick = DateTime.UtcNow.Ticks;
            double delta = new TimeSpan(tick - lastTick).TotalSeconds;
            lastTick = tick;
            return delta;
        }


        private long lastTick;

        //private double lastrefreshprint;
        //private double deltaprint;
        //private double FPS;
        //private long framesprint;

        double TimeSinceLastRefresh = 0;
        int MaxFPS = 100;

        //double second = 0;
        //int frames = 0;

        double delta;

        /// <summary>
        /// Allows the page to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        private void OnUpdate(object sender, GameTimerEventArgs e)
        {
            // TODO: Add your update logic here

            delta = GetDelta();
            delta = e.ElapsedTime.TotalSeconds;
            TimeSinceLastRefresh += delta;
            //second += delta;

            //if (TimeSinceLastRefresh >= 1.0f / MaxFPS)
            //{
            //    RenderPositions();
            //    frames++;
            //    if (second > 1)
            //    {
            //        framesprint = frames;
            //        FPS = frames / second;
            //        textBlock1.Text = string.Format("FPS:{0}", FPS);

            //        second = 0;
            //        frames = 0;
            //    }
            //    lastrefreshprint = TimeSinceLastRefresh;
            //    deltaprint = delta;

            //    TimeSinceLastRefresh -= (1.0f / MaxFPS);

            //}

            World.Step(Math.Min((float)e.ElapsedTime.TotalSeconds, (1f / 30f)));

            foreach (ShakeObject so in App.shakeObjects)
            {
                so.Movement(delta);

            }
            processMouse();
        }



        //TouchCollection _lastMouseState =new TouchCollection();
        //TouchCollection _currentMouseState = new TouchCollection();
        ///// <summary>
        /////   Helper for checking if a button was newly pressed during this update.
        ///// </summary>
        //public bool IsNewButtonPress()
        //{
        //    return (_lastMouseState.LeftButton == ButtonState.Pressed &&
        //            _currentMouseState.LeftButton == ButtonState.Released);
        //}

        //public bool IsNewButtonRelease()
        //{
        //    return (_lastMouseState.LeftButton == ButtonState.Released &&
        //            _currentMouseState.LeftButton == ButtonState.Pressed);
        //}

        FixedMouseJoint _fixedMouseJoint;
        private void processMouse()
        {
            TouchCollection _currentMouseState = Microsoft.Xna.Framework.Input.Touch.TouchPanel.GetState();
            if (_currentMouseState.Count == 1){
            //foreach (TouchLocation location in _currentMouseState)
            //{
                TouchLocation location = _currentMouseState.First();
                Vector2 position = ConvertUnits.ToSimUnits(location.Position);

                if (location.State == TouchLocationState.Pressed &&
                    _fixedMouseJoint == null)
                {
                    Fixture savedFixture = World.TestPoint(position);
                    if (savedFixture != null)
                    {
                        Body body = savedFixture.Body;
                        _fixedMouseJoint = new FixedMouseJoint(body, position);
                        _fixedMouseJoint.MaxForce = 1000.0f * body.Mass;
                        World.AddJoint(_fixedMouseJoint);
                        body.Awake = true;
                    }
                }

                if (location.State == TouchLocationState.Released &&
                    _fixedMouseJoint != null)
                {
                    World.RemoveJoint(_fixedMouseJoint);
                    _fixedMouseJoint = null;
                }

                if (_fixedMouseJoint != null)
                {
                    _fixedMouseJoint.WorldAnchorB = position;
                }
            }
            //_lastMouseState = _currentMouseState;
        }


        /// <summary>
        /// Allows the page to draw itself.
        /// </summary>
        private void OnDraw(object sender, GameTimerEventArgs e)
        {
            SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.CornflowerBlue);



            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);


            spriteBatch.Draw(backgroundTexture, App.ShakeImagePos, Color.White);
            //LineBatch.DrawLine(spriteBatch, Color.Red, App.ShakeImagePos, Vector2.Add( App.ShakeImagePos,new Vector2(backgroundTexture.Width,0)));
            //LineBatch.DrawLine(spriteBatch, Color.Red, App.ShakeImagePos, Vector2.Add(App.ShakeImagePos, new Vector2(0, backgroundTexture.Height)));
            //LineBatch.DrawLine(spriteBatch, Color.Red, Vector2.Add(App.ShakeImagePos, new Vector2(backgroundTexture.Width, 0)), Vector2.Add(App.ShakeImagePos, new Vector2(backgroundTexture.Width, backgroundTexture.Height)));
            //LineBatch.DrawLine(spriteBatch, Color.Red, Vector2.Add(App.ShakeImagePos, new Vector2(0, backgroundTexture.Height)), Vector2.Add(App.ShakeImagePos, new Vector2(backgroundTexture.Width, backgroundTexture.Height)));

            Drawrectangle(App.ShakeImagePos, Vector2.Add(App.ShakeImagePos, new Vector2(backgroundTexture.Width, backgroundTexture.Height)));

            //spriteBatch.Draw(testTxt, ConvertUnits.ToDisplayUnits(_rectangle.Position),
            //                             null,
            //                              Color.White, _rectangle.Rotation, Vector2.Zero, 1, SpriteEffects.None, 0);
            //LineBatch.DrawLine(spriteBatch, Color.Red, ConvertUnits.ToDisplayUnits(joint.WorldAnchorA), ConvertUnits.ToDisplayUnits(joint.WorldAnchorB));
            LineBatch.DrawLine(spriteBatch, Color.Green, new Vector2(40, 40), Vector2.Add(new Vector2(40, 40), World.Gravity));
            foreach (ShakeObject so in App.shakeObjects)
            {
                so.Render(spriteBatch);
            }
            int i;
            for ( i = 0; i < App.StepFraction - App.minStep; i++)
            {
                foreach (ShakeObject so in App.shakeObjects)
                {
                    spriteBatch.Draw(so.texturesList[i], (Vector2)so.texturesList[i].Tag, Microsoft.Xna.Framework.Color.White);
                }
            }

            //foreach (ShakeObject so in App.shakeObjects)
            //{
            //    //spriteBatch.Draw(so.circle, (Vector2)so.texturesList[0].Tag, Microsoft.Xna.Framework.Color.White);
            //    spriteBatch.Draw(so.circle, (Vector2)so.circle.Tag, Microsoft.Xna.Framework.Color.White);
            //}

            spriteBatch.End();

            // TODO: Add your drawing code here
        }

        void Drawrectangle(Vector2 p1, Vector2 p2)
        {
            Texture2D rect = new Texture2D(SharedGraphicsDeviceManager.Current.GraphicsDevice, (int)(p2.X - p1.X), (int)(p2.Y - p1.Y));

            Color[] data = new Color[rect.Width * rect.Height];
            for (int i = 0; i < rect.Width; ++i) data[i] = Color.Red;
            for (int i = rect.Width * (rect.Height - 1); i < rect.Width * rect.Height; ++i) data[i] = Color.Red;
            for (int i = 0; i < rect.Width * rect.Height; i = i + rect.Width) data[i] = Color.Red;
            for (int i = rect.Width-1; i < rect.Width * rect.Height; i = i + rect.Width) data[i] = Color.Red;
            rect.SetData(data);

            Vector2 coor = p1;
            spriteBatch.Draw(rect, p1, Color.White);

        }

        void startstop(bool command)
        {
            // If the accelerometer is null, it is initialized and started
            if (AccelerometerHelper.Instance.Active == false && command == true)
            {
                //// Instantiate the accelerometer sensor object
                //accelerometer = new Accelerometer();

                //// Add an event handler for the ReadingChanged event.
                //accelerometer.ReadingChanged += new EventHandler<AccelerometerReadingEventArgs>(accelerometer_ReadingChanged);

                //// The Start method could throw and exception, so use a try block
                //try
                //{
                //    textBlock2.Text = "starting accelerometer";
                //    accelerometer.Start();
                //}
                //catch (AccelerometerFailedException exception)
                //{
                //    textBlock2.Text = "error starting accelerometer";
                //}

                AccelerometerHelper.Instance.Active = true;


                accelerometerLastTick = DateTime.UtcNow.Ticks;

            }
            else if (command == false)
            {
                // if the accelerometer is not null, call Stop
                //try
                //{
                //    accelerometer.Stop();
                //    accelerometer = null;
                //    textBlock2.Text = "accelerometer stopped";
                //}
                //catch (AccelerometerFailedException exception)
                //{
                //    textBlock2.Text = "error stopping accelerometer";
                //}
                AccelerometerHelper.Instance.Active = false;
            }
        }
        Simple3DVector previousReading;


        private void OnAccelerometerHelperReadingChanged(object sender, AccelerometerHelperReadingEventArgs e)
        {

            //e.RawAcceleration.ToString();
            //e.LowPassFilteredAcceleration.ToString();
            //e.OptimalyFilteredAcceleration.ToString();
            //e.AverageAcceleration.ToString();
            Simple3DVector acc = e.LowPassFilteredAcceleration;
            if (previousReading == null) previousReading = acc;
            Dispatcher.BeginInvoke(() =>
            {

                double accdelta = GetAccelerometerDelta();
                //double magnitude = Math.Abs(acc.Magnitude - previousReading.Magnitude);
                //if (magnitude > 0.05 && accdelta > 0)
                //{
                //    System.Windows.Point pnt = new System.Windows.Point(Math.Abs(acc.X) * magnitude * 1000 * (acc.X - previousReading.X) / accdelta, Math.Abs(acc.Y) * magnitude * 1000 * (acc.Y - previousReading.Y) / accdelta);
                if (double.IsInfinity(acc.X))
                {
                    return;
                }

                //textBlock2.Text = String.Format("{0}\n{1}\n{2}\n{3}", acc.Magnitude.ToString(), pnt.X.ToString("0.00"), pnt.Y.ToString("0.00"), acc.Z.ToString("0.00"));
                //Canvas.SetLeft(this, Canvas.GetLeft(this) + (pnt.X - ImageDragPoint.X));
                //Canvas.SetTop(this, Canvas.GetTop(this) + (pnt.Y - ImageDragPoint.Y));
                //foreach (ShakeObject obj in App.shakeObjects)
                //{
                //    obj.Move(acc);
                //}
                //}

                World.Gravity = new Vector2((float)acc.X * gravityRatio, -(float)acc.Y * gravityRatio);
                previousReading = acc;

            }
            );
        }
        float gravityRatio = 100f;
        long accelerometerLastTick;

        private double GetAccelerometerDelta()
        {
            long tick = DateTime.UtcNow.Ticks;
            double accdelta = new TimeSpan(tick - accelerometerLastTick).TotalSeconds;
            accelerometerLastTick = tick;
            return accdelta;
        }

    }
}